package com.javasm.proxy1;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 *  代理模式:对一个已经存在的对象来说,当对象中的某个方法不满足需求的时候,在不改动原对象代码的情况下,引入代理模式进行扩展.
 *
 * 动态代理 ：与静态代理没有本质上的区别,不用开发人员再去手工创建代理类,在程序运行期间,动态的在内存中创建代理类.并进行编译,进行实例化得到代理对象.
 * 方式：
 *   jdk:Proxy工具类， 动态代理机制中有两个重要的类和接口InvocationHandler（接口）和Proxy（类）
 *   第三方的:cglib组件
 *
 * @remark:
 */
public class TestSource2 {
    public static void main(String[] args) {
        //设置jvm虚拟机参数,保存代理类,可以查看代理类的结构
        System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
        //原对象SourceImpl()
        ISource source = new SourceImpl();

        //动态代理对象， 不用开发人员再去手工创建代理类


        //参数1： ClassLoader 是一个类加载器， 根据ISource类获取ClassLoader对象
        ClassLoader loader = ISource.class.getClassLoader();
        // 参数2：提供源对象接口对象，用于jvm内部创建代理类，表示从源对象接口ISource派生的  （根据静态代理  SourceProxy implements ISource 创建代理类需要实现源对象的接口进行派生 ）
        Class[] interfaces = new Class[]{ISource.class};

        //参数3： InvocationHandler处理器：调用处理程序的invoke方法   动态代理的核心
       // InvocationHandler接口：此接口没有实现类，需要派生实现类（自定义处理器类implements nvocationHandler接口并重写invoke（）方法 ）
                                 //或者匿名内部类，进行重写 invoke（）方法
        //代理对象调用sourceProxy.begin()方法后，才会进行回调处理器InvocationHandler对象的invoke（）方法
        InvocationHandler h = new InvocationHandler() {//  InvocationHandler接口：匿名内部类
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //获取类的方法
                Method m = Class.forName("InvocationHandler").getMethod("end");
                //获取类的方法名
                String name = method.getName();
                if ("end".equals(name)) {
                    System.out.println("返回连接池");
                } else {
                    //调用源对象source对象中的对应方法begin
                    Object result = method.invoke(source, args);//invoke（）当前方法是Method的方法，是源对象的方法；即是源对象的invoke（）方法
                    return result;
                }
                return null;
            }
        };
        //要求被代理对象必须有接口;  invoke方法的第一个参数是代理对象,绝对不能显示的调用此对象,只能作为参数传递
        ISource sourceProxy = (ISource) Proxy.newProxyInstance(loader, interfaces, h);

        String r = sourceProxy.begin(1);//代理对象调用begin()方法后，进行回调处理器InvocationHandler对象的invoke（）方法，内部调用源对象的begin()方法
        sourceProxy.end();//代理对象调用end()方法后，进行回调处理器InvocationHandler对象的invoke（）方法，内部处理自定义的end（）方法
    }

}
